#include "stdafx.h"

#include "hwincontrol.h"
#include "hwinapplication.h"
#include "hwinmenu.h"
#include "hwincomcontrol.h"
#include <typeinfo>

namespace harlinn
{
    namespace windows
    {
        // --------------------------------------------------------------------
        // Controls
        // --------------------------------------------------------------------
        HWIN_EXPORT Controls::Controls(Control* theControl)
            : control(theControl)
        {
            if(!theControl)
            {
                ThrowPointerIsNULL();
            }
        }

        HWIN_EXPORT void Controls::DoOnHandleCreated( )
        {
            for(auto weakItem : items)
            {
                auto item = weakItem.lock();
                if(item)
                {
                    item->GetSafeHandle();
                }
            }
        }

        HWIN_EXPORT void Controls::DoBeforeHandleDestroy( )
        {
        }

        HWIN_EXPORT void Controls::Remove(const std::shared_ptr< Control >& theControl)
        {
            if(theControl)
            {
                for(auto it = items.begin(); it != items.end(); it++)
                {
                    auto item = (*it).lock();
                    if(item == theControl)
                    {
                        items.erase(it);
                        break;
                    }
                }
            }
        }
        HWIN_EXPORT void Controls::Add(const std::shared_ptr< Control >& theControl)
        {
            if(theControl)
            {
                if(Contains(theControl) == false)
                {
                    items.push_back(theControl);
                }
            }
        }


        HWIN_EXPORT void Controls::DisconnectParentControl()
        {
            for(auto weakItem : items)
            {
                auto item = weakItem.lock();
                if(item)
                {
                    item->DisconnectParentControl();
                }
            }
        }



        HWIN_EXPORT bool Controls::Contains(const std::shared_ptr< const Control >& theChildControl) const
        {
            
            bool result = false;
            if(theChildControl)
            {
                for(auto weakItem : items)
                {
                    auto item = weakItem.lock();
                    if(item == theChildControl)
                    {
                        result = true;
                        break;
                    }
                }
            }
            return result;
        }

        // --------------------------------------------------------------------
        // ControlWindowClass
        // --------------------------------------------------------------------
        class ControlWindowClass : public WindowClass
        {
        public:
            static String HWIN_EXPORT ClassName;

            HWIN_EXPORT ControlWindowClass();
        };

        String HWIN_EXPORT ControlWindowClass::ClassName = String(L"HarlinnWindowsControlWindowClassName");

        typedef ControlMessageDispatcher<Control> DefaultControlMessageDispatcher;

        HWIN_EXPORT ControlWindowClass::ControlWindowClass()
        {
            SetName(ClassName);
            WNDPROC procedure = DefaultControlMessageDispatcher::WndProc;
            SetProcedure(procedure);
            
        }


        // --------------------------------------------------------------------
        // Control
        // --------------------------------------------------------------------
        UINT Control::REFLECTED_WM_COMMAND = RegisterWindowMessage(L"Control::REFLECTED_WM_COMMAND");
        UINT Control::REFLECTED_WM_NOTIFY = RegisterWindowMessage(L"Control::REFLECTED_WM_NOTIFY");
        UINT Control::REFLECTED_WM_DRAWITEM = RegisterWindowMessage(L"Control::REFLECTED_WM_DRAWITEM");
        UINT Control::WM_GET_CONTROL = RegisterWindowMessage(L"Control::WM_GET_CONTROL");


        HWIN_EXPORT Control::Control( )
            : Base( ), 
              handle(0),
              id(0),
              dock(DockStyle::None),
              enabled(true),
              visible(true),
              tabStop(true),
              recreatingHandle(false),
              anchorStyles(AnchorStyles::Left | AnchorStyles::Top),
              automaticallyAddParentlessOwnedControls(true),
              originalWindowsProcedure(nullptr),
              position(CW_USEDEFAULT,CW_USEDEFAULT),
              size(CW_USEDEFAULT,CW_USEDEFAULT)
        {
            

            controls = std::make_shared<harlinn::windows::Controls>(this);
            
        }


        HWIN_EXPORT Control::~Control()
        {
            SetParent(nullptr);
            DisconnectParentControl();
            if(handle)
            {
                DestroyHandle();
            }
            
        }

        HWIN_EXPORT ComObject* Control::CreateComObject() const
        {
            auto self = std::const_pointer_cast< Control, const Control >(As<Control>());
            ComControl* result = new ComControl(self);
            return result;
        }

        HWIN_EXPORT void Control::DoOnInitialize( )
        {
            Base::DoOnInitialize();    
        }


        HWIN_EXPORT std::shared_ptr<WindowClass> Control::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(ControlWindowClass::ClassName);
            if(!windowClass)
            {
                auto newWindowClass = std::make_shared<ControlWindowClass>();
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }

        HWIN_EXPORT DWORD Control::GetStyle() const
        {
            DWORD result = WS_CHILD;
            if(visible)
            {
                result |= WS_VISIBLE;
            }
            if(tabStop)
            {
                result |= WS_TABSTOP;
            }
            if(!enabled)
            {
                result |= WS_DISABLED;
            }
            return result;
        }


        HWIN_EXPORT DWORD Control::GetStyleEx() const
        {
            return 0;
        }

        HWIN_EXPORT Control& Control::SetWindowStyle(DWORD theStyle)
        {
            SetWindowLong(GWL_STYLE,theStyle);
            return *this;
        }
        HWIN_EXPORT Control& Control::SetWindowStyleEx(DWORD theExStyle)
        {
            SetWindowLong(GWL_EXSTYLE,theExStyle);
            return *this;
        }

        HWIN_EXPORT void Control::RecreateHandle()
        {
            if(controls->items.size())
            {
                throw InvalidOperationException("RecreateHandle called for a control with children");
            }
            if((IsSubClassed() == false)&&(IsValid()))
            {
                try
                {
                    recreatingHandle = true;
                    this->DoOnBeforeRecreatingHandle();
                    ::DestroyWindow(handle);
                    handle = this->CreateHandle();
                    this->DoOnAfterRecreatingHandle();
                }
                catch(...)
                {
                    recreatingHandle = false;
                    throw;
                }
                recreatingHandle = false;
            }
        }
        HWIN_EXPORT void Control::DoOnBeforeRecreatingHandle()
        {
        }
        HWIN_EXPORT void Control::DoOnAfterRecreatingHandle()
        {
        }



        HWIN_EXPORT bool Control::IsChild() const
        {
            bool result = (GetStyle() & WS_CHILD) != 0;
            return result;
        }
        HWIN_EXPORT bool Control::IsToplevel() const
        {
            bool result = (GetStyle() & WS_CHILD) == 0;
            return result;
        }
        HWIN_EXPORT bool Control::IsPopup() const
        {
            bool result = (GetStyle() & WS_POPUP) != 0;
            return result;
        }


        HWIN_EXPORT bool Control::Enabled() const
        {
            return enabled;
        }
        HWIN_EXPORT Control& Control::SetEnabled(bool theValue)
        {
            if(theValue != enabled)
            {
                this->DoOnSetEnabled(theValue);
                enabled = theValue;
            }
            return *this;
        }

        HWIN_EXPORT bool Control::Visible() const
        {
            return visible;
        }
        HWIN_EXPORT Control& Control::SetVisible(bool theValue)
        {
            if(visible != theValue)
            {
                visible = theValue;
                if(IsHandleCreated())
                {
                    if(SetWindowPos(handle,
                                    nullptr,
                                    0, 0, 0, 0, 
                                    SWP_NOSIZE
                                    | SWP_NOMOVE 
                                    | SWP_NOZORDER 
                                    | SWP_NOACTIVATE
                                    | (theValue ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)) == 0)
                    {
                        ThrowLastOSError();
                    }
                }
            }
            return *this;
        }

        HWIN_EXPORT bool Control::TabStop() const
        {
            return tabStop;
        }
        HWIN_EXPORT Control& Control::SetTabStop(bool theValue)
        {
            if(tabStop != theValue)
            {
                tabStop = theValue;
                if(IsHandleCreated())
                {
                    DWORD style = this->GetStyle();
                    SetWindowStyle(style);
                }
            }
            return *this;
        }

        
        HWIN_EXPORT void Control::DoOnSetEnabled(bool theValue)
        {
        }

        HWIN_EXPORT long Control::Id() const
        {
            return id;
        }
        HWIN_EXPORT Control& Control::SetId(long theValue)
        {
            if(id != theValue)
            {
                id = theValue;
                if(IsValid())
                {
                    SetWindowLong(GWL_ID,theValue);
                }
            }
            return *this;
        }


        HWIN_EXPORT HWND Control::CreateHandle( )
        {
            auto windowClass = this->GetWindowClass();
            HWND result = NULL;
            if(windowClass)
            {
                const String& className = windowClass->GetName();
                if(className.length())
                {
                    HWND hWndParent = 0;
                    auto theParentControl = parentControl.lock();
                    if(theParentControl)
                    {
                        hWndParent = theParentControl->GetSafeHandle();
                    }
                    result = ::CreateWindowExW(this->GetStyleEx(),
                        className.c_str(),
                        nullptr,this->GetStyle(),
                        position.X(), position.Y(), size.Width(), size.Height(), 
                        hWndParent,0,0,(LPVOID)this);
                    if(!result)
                    {
                        ThrowLastOSError();
                    }
                }
            }
            return result;
        }

        HWIN_EXPORT void Control::DoOnHandleCreated( )
        {
            if(text.length())
            {
                ::SetWindowTextW(handle,text.c_str());
            }
            if(id)
            {
                SetWindowLong(GWLP_ID,id);
            }
            if(automaticallyAddParentlessOwnedControls)
            {
                auto theComponents = this->GetComponents();
                for(auto it = theComponents->begin();it != theComponents->end(); it++)
                {
                    auto theComponent = *it;
                    if(theComponent->Is<Control>())
                    {
                        auto theControl = theComponent->As<Control>();
                        if( (theControl->HasParent() == false )&& ((theControl->GetStyle() & WS_CHILD) != 0))
                        {
                            theControl->SetParent(As<Control>());
                        }
                    }
                }
            }
            this->DoOnSetEnabled(Enabled());
            controls->DoOnHandleCreated();
        }


        HWIN_EXPORT void Control::DestroyHandle( )
        {
            if(IsValid())
            {
                this->DoBeforeHandleDestroy( );
                bool succeeded = ::DestroyWindow(handle) != FALSE;
                handle = NULL;
                if(!succeeded)
                {
                    ThrowLastOSError();
                }
            }
            handle = NULL;
        }

        HWIN_EXPORT void Control::DoBeforeHandleDestroy( )
        {

        }

        HWIN_EXPORT void Control::DisconnectParentControl()
        {
            controls->DisconnectParentControl();
            parentControl = std::weak_ptr<Control>();
        }


        HWIN_EXPORT Control& Control::RestoreSubClassedWindowsProcedure()
        {
            if(IsSubClassed() && handle)
            {
                SetWindowLongPtrW(handle,GWLP_WNDPROC,LONG_PTR(originalWindowsProcedure));
            }
            return *this;
        }

        LRESULT CALLBACK Control::SubClassWndProc(HWND hWnd, UINT messageId, WPARAM wParam, LPARAM lParam)
        {
            Message message;
            message.hwnd = hWnd;
            message.message = messageId;
            message.wParam = wParam;
            message.lParam = lParam;
            message.time = GetMessageTime();
            DWORD pos = GetMessagePos();

            message.pt.x = GET_X_LPARAM(pos);
            message.pt.y = GET_Y_LPARAM(pos);

            LONG_PTR userData = (LONG_PTR)0;

            userData = GetWindowLongPtr(hWnd,GWLP_USERDATA);

            if(userData)
            {
                Control* control = (Control*)userData;

                control->HandleMessage(message);
                if(!message.handled)
                {
                    message.result = control->originalWindowsProcedure(hWnd, message.message, message.wParam, message.lParam);
                }
                if(messageId == WM_NCDESTROY)
                {
                    control->RestoreSubClassedWindowsProcedure();
                }
            }
            

            if(messageId == WM_NCDESTROY)
            {
                Control::UnregisterControl(hWnd);
            }
            return message.result;
        }
        
        HWIN_EXPORT Control& Control::SubClass(HWND hWnd)
        {
            
            if(IsSubClassed())
            {
                throw InvalidOperationException("Window is already subclassed");
            }
            Message::Result res = ::SendMessageW(hWnd,WM_GET_CONTROL,0,0);
            if(res)
            {
                throw InvalidOperationException("Window should not be subclassed, it's already a Control");
            }
            
            originalWindowsProcedure = (WNDPROC)GetWindowLongPtrW(handle,GWLP_WNDPROC);
            SetWindowLongPtrW(handle,GWLP_WNDPROC,LONG_PTR(SubClassWndProc));
            SetWindowLongPtrW(hWnd,GWLP_USERDATA,LONG_PTR(this));
            Control::RegisterControl(hWnd,this);

            return *this;
        }
        HWIN_EXPORT bool Control::IsSubClassed() const
        {
            return originalWindowsProcedure != nullptr;
        }

        HWIN_EXPORT void Control::DoOnWindowSubClassed( )
        {

        }


        HWIN_EXPORT HWND Control::GetSafeHandle() const
        {
            if(!handle)
            {
                Control* self = const_cast<Control*>(this);
                self->handle = self->CreateHandle( );
                self->DoOnHandleCreated( );
            }
            return handle;
        }

        HWIN_EXPORT bool Control::IsHandleCreated() const
        {
            return handle != 0;
        }


        HWIN_EXPORT const Control& Control::GetClientRect(RECT* rectangle) const
        {
            CheckPointerNotNull(rectangle);
            if(::GetClientRect(GetSafeHandle(),rectangle) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT const Control& Control::GetClientRect(RECT& rectangle) const
        {
            if(::GetClientRect(GetSafeHandle(),&rectangle) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT RECT Control::GetClientRect( ) const
        {
            RECT result;
            if(::GetClientRect(GetSafeHandle(),&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }


        HWIN_EXPORT D2D1_SIZE_F Control::ClientSize() const
        {
            RECT rect;
            if(::GetClientRect(GetSafeHandle(),&rect) == FALSE)
            {
                ThrowLastOSError();
            }
            D2D1_SIZE_F result;
            result.width = float(rect.right - rect.left);
            result.height = float(rect.bottom - rect.top);
            return result;
        }


        
        

        HWIN_EXPORT void Control::RegisterControl(HWND hWnd,Control* constrol)
        {
            auto application = Application::Current();
            if(application)
            {
                application->AddControl(hWnd,constrol);
            }

        }

        HWIN_EXPORT void Control::UnregisterControl(HWND hWnd)
        {
            auto application = Application::Current();
            if(application)
            {
                application->RemoveControl(hWnd);
            }
        }

        HWIN_EXPORT Control* Control::GetControlFromHWND(HWND hWnd)
        {
            auto application = Application::Current();
            if(application)
            {
                Control* result = application->GetControl(hWnd);
                return result;
            }
            return nullptr;
        }

        


        HWIN_EXPORT std::shared_ptr<Controls> Control::Controls() const
        {
            return controls;
        }

        HWIN_EXPORT std::shared_ptr<Control> Control::Parent() const
        {
            return parentControl.lock();
        }
        HWIN_EXPORT Control& Control::SetParent(std::shared_ptr<Control> theParentControl)
        {
            auto currentParent = Parent();
            if(theParentControl != currentParent)
            {
                auto self = As<Control>();
                if(theParentControl)
                {
                    if(theParentControl->IsChildOf(self))
                    {
                        throw InvalidOperationException("Attempted to create a cyclic parent/child control relationship.");
                    }
                    if(currentParent)
                    {
                        currentParent->Controls()->Remove(self);
                    }
                    theParentControl->Controls()->Add(self);
                    parentControl = theParentControl;
                    if(theParentControl->IsValid())
                    {
                        if(IsValid() == false)
                        {
                            GetSafeHandle();
                        }
                        else
                        {
                            if(::SetParent(handle,theParentControl->handle) == FALSE)
                            {
                                ThrowLastOSError();
                            }    
                        }
                    }
                    else
                    {
                        this->DestroyHandle();
                    }
                    
                }
                else if(currentParent)
                {
                    currentParent->Controls()->Remove(self);
                    parentControl = std::weak_ptr<Control>();
                    if(handle)
                    {
                        if((this->GetStyle() & WS_CHILD) == 0)
                        {
                            if(State() == ComponentState::Destructing)
                            {
                                if(::SetParent(handle,NULL) == FALSE)
                                {
                                    ThrowLastOSError();
                                }
                            }
                        }
                        else
                        {
                            this->DestroyHandle();
                        }
                    }
                
                }
            }
            return *this;
        }

        HWIN_EXPORT bool Control::HasParent() const
        {
            return parentControl.lock().get() != nullptr;
        }


        HWIN_EXPORT const Control& Control::UpdateRect(RECT& updateRectangle) const
        {
            if(GetUpdateRect(GetSafeHandle(),&updateRectangle,false) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT Control& Control::UpdateRect(RECT& updateRectangle, bool erase)
        {
            if(GetUpdateRect(GetSafeHandle(),&updateRectangle,erase) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT RECT Control::UpdateRect( ) const
        {
            RECT result = {0,};
            if(GetUpdateRect(GetSafeHandle(),&result,false) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }
        HWIN_EXPORT RECT Control::UpdateRect( bool erase )
        {
            RECT result = {0,};
            if(GetUpdateRect(GetSafeHandle(),&result,erase) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }


        /*
        BOOL CALLBACK EnumChildWindowsProcedure(HWND hWnd, LPARAM lParam)
        {
            std::vector< Control* >* vector = (std::vector< Control* >*)lParam;

            Control* control = Control::GetControlFromHWND(hWnd);
            if(control)
            {
                vector->push_back(control);
            }
            return TRUE;
        }

        HWIN_EXPORT std::vector< Control* > Control::GetChildren() const
        {
            std::vector< Control* > result;
            LPARAM lParam = (LPARAM)&result;

            // Even if EnumChildWindows has a return type of BOOL the return value is not used
            ::EnumChildWindows(GetSafeHandle(),EnumChildWindowsProcedure,lParam);

            return result;
        }
        */

        HWIN_EXPORT bool Control::IsChildOf(std::shared_ptr<const Control> theParentControl) const
        {
            bool result = false;
            if(theParentControl)
            {
                 auto pControl = Parent();
                 while(pControl)
                 {
                     if(pControl == theParentControl)
                     {
                         result = true;
                         break;
                     }
                     pControl = pControl->Parent();
                 }
            }
            return result;
        }

        HWIN_EXPORT bool Control::IsChildOf(HWND theParentControl) const
        {
            bool result = ::IsChild(theParentControl,GetSafeHandle()) != FALSE;
            return result;
        }

        HWIN_EXPORT bool Control::IsParentOf(std::shared_ptr<const Control> theChildControl) const
        {
            bool result = false;
            if(theChildControl)
            {
                result = theChildControl->IsChildOf(As<Control>());
            }
            return result;
        }

        HWIN_EXPORT bool Control::IsParentOf(HWND theChildControl) const
        {
            bool result = ::IsChild(GetSafeHandle(),theChildControl) != FALSE;
            return result;
        }

        HWIN_EXPORT bool Control::IsValid() const
        {
            bool result = false;
            if(handle)
            {
                result = ::IsWindow(handle) != FALSE;
            }
            return result;
        }

        HWIN_EXPORT bool Control::IsVisible() const
        {
            bool result = false;
            if(handle)
            {
                result = ::IsWindowVisible(handle) != FALSE;
            }
            return result;
        }

        HWIN_EXPORT Control& Control::InvalidateRect(bool erase)
        {
            if(handle)
            {
                if(::InvalidateRect(handle,NULL,erase) == FALSE)
                {
                    ThrowLastOSError();
                }
            }
            return *this;
        }
        HWIN_EXPORT Control& Control::InvalidateRect(const RECT& rectangle,bool erase)
        {
            if(handle)
            {
                if(::InvalidateRect(handle,&rectangle,erase) == FALSE)
                {
                    ThrowLastOSError();
                }
            }
            return *this;
        }

        HWIN_EXPORT Control& Control::MoveWindow(int x, int y, int width, int height, bool repaint)
        {
            if(handle)
            {
                if(::MoveWindow(handle,x,y,width, height, repaint) == FALSE)
                {
                    ThrowLastOSError();
                }
            }
            position.Set(x,y);
            size.Set(width,height);
            
            return *this;
        }

        HWIN_EXPORT LONG Control::SetWindowLong(int index, LONG theNewValue)
        {
            if(IsValid() == false)
            {
                throw InvalidOperationException("Valid window handle required");
            }
            SetLastError(0);

            LONG result = ::SetWindowLong(handle,index, theNewValue);

            if(GetLastError() != 0)
            {
                ThrowLastOSError();
            }
            return result;
        }
        HWIN_EXPORT LONG Control::GetWindowLong(int index) const
        {
            if(IsValid() == false)
            {
                throw InvalidOperationException("Valid window handle required");
            }
            SetLastError(0);

            LONG result = ::GetWindowLong(handle,index);

            if(GetLastError() != 0)
            {
                ThrowLastOSError();
            }
            return result;
        }


        HWIN_EXPORT LRESULT Control::SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam ) const
        {
            return ::SendMessage(GetSafeHandle(),Msg, wParam, lParam);
        }

        HWIN_EXPORT const Control& Control::PostMessage(UINT Msg, WPARAM wParam, LPARAM lParam) const
        {
            if(::PostMessage(GetSafeHandle(),Msg, wParam, lParam) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT int Control::TextLength() const
        {
            int size = ::GetWindowTextLengthW(GetSafeHandle());
            return size;
        }
        
        HWIN_EXPORT String Control::Text() const
        {
            int size = ::GetWindowTextLengthW(GetSafeHandle());
            if(size > 0)
            {
                wchar_t *buffer = (wchar_t *)alloca((size + 1)*sizeof(wchar_t));

                ::GetWindowTextW(handle,buffer,size+1);

                String result = String(buffer);
                return result;
            }
            else
            {
                return String();
            }
        }


        HWIN_EXPORT bool Control::SetText(const String& theText)
        {
            bool result = true;
            if(handle)
            {
                result = ::SetWindowText(GetSafeHandle(),theText.c_str()?theText.c_str():L"") != FALSE;
            }
            text = theText;
            return result;
        }
        HWIN_EXPORT bool Control::SetText(const wchar_t* theText)
        {
            bool result = true;
            if(handle)
            {
                if((theText)&&(theText[0]))
                {
                    result = ::SetWindowText(GetSafeHandle(),theText) != FALSE;
                }
                else
                {
                    result = ::SetWindowText(GetSafeHandle(),L"") != FALSE;
                }
            }
            if((theText)&&(theText[0]))
            {
                text = theText;
            }
            else
            {
                text = String();
            }
            return result;
        }


        HWIN_EXPORT bool Control::Show()
        {
            bool result = ::ShowWindow(GetSafeHandle(),SW_SHOW) != FALSE;
            return result;
        }

        HWIN_EXPORT bool Control::ValidateRect(const RECT& rectangle)
        {
            bool result = ::ValidateRect(GetSafeHandle(),&rectangle) != FALSE;
            return result;
        }

        HWIN_EXPORT bool Control::ValidateRect( )
        {
            bool result = ::ValidateRect(GetSafeHandle(),NULL) != FALSE;
            return result;
        }


        HWIN_EXPORT harlinn::windows::Size Control::Size() const
        {
            return size;
        }

        HWIN_EXPORT Control& Control::SetSize(int width, int height)
        {
            if(IsHandleCreated())
            {
                MoveWindow(position.X(),position.Y(),width,height);
            }
            else
            {
                size = harlinn::windows::Size(width,height);
            }
            return *this;
        }

        HWIN_EXPORT Control& Control::SetSize(const harlinn::windows::Size& theSize)
        {
            if(IsHandleCreated())
            {
                MoveWindow(position.X(),position.Y(),theSize.Width(),theSize.Height());
            }
            else
            {
                size = theSize;
            }
            return *this;
        }
        
        
        HWIN_EXPORT Point Control::Position() const
        {
            return position;
        }
        HWIN_EXPORT Control& Control::SetPosition(int x, int y)
        {
            if(IsHandleCreated())
            {
                MoveWindow(x,y,size.Width(),size.Height());
            }
            else
            {
                position.Set(x,y);
            }
            return *this;
        }
        HWIN_EXPORT Control& Control::SetPosition(const Point& thePosition)
        {
            if(IsHandleCreated())
            {
                MoveWindow(thePosition.X(),thePosition.Y(),size.Width(),size.Height());
            }
            else
            {
                position.Set(thePosition.X(),thePosition.Y());
            }
            return *this;
        }



        HWIN_EXPORT bool Control::IsInputChar(wchar_t charCode)
        {
            int mask = DLGC_WANTCHARS | DLGC_WANTALLKEYS; 
            if (charCode == (wchar_t)Keys::Tab) 
            { 
                mask |= DLGC_WANTTAB;
            } 
            if (IsHandleCreated()) 
            { 
                return (SendMessage(WM_GETDLGCODE) & mask) != 0;
            } 
            return false;
        }

        HWIN_EXPORT bool Control::IsInputKey(Keys keyData)
        {
            if ((keyData & Keys::Alt) == Keys::Alt) 
            {
                return false;
            }
            int mask = DLGC_WANTALLKEYS; 
            int keyCode = int(keyData & Keys::KeyCode);
            switch (keyCode) 
            {
                case Keys::Tab:
                    mask |= DLGC_WANTTAB;
                    break; 
                case Keys::Left:
                case Keys::Right: 
                case Keys::Up: 
                case Keys::Down:
                    mask |= DLGC_WANTARROWS; 
                    break;
            }

            if (IsHandleCreated()) 
            { 
                return (SendMessage(WM_GETDLGCODE) & mask) != 0;
            } 
            return false;
        }

        HWIN_EXPORT bool Control::ProcessMnemonic(wchar_t charCode)
        {
            return false;
        }



        HWIN_EXPORT void Control::HandleMessage(Message& message)
        {
            if(message.message == REFLECTED_WM_COMMAND)
            {
                this->DoOnCommand(message);
                message.result = 1;
            }
            else if(message.message == REFLECTED_WM_NOTIFY)
            {
                this->DoOnNotify(message);
            }
            else if(message.message == REFLECTED_WM_DRAWITEM)
            {
                this->DoOnDrawItem(message);
            }
            else if(message.message == WM_GET_CONTROL)
            {
                message.handled = true;
                message.result = (Message::Result)this;
            }
            else
            {
                switch(message.message)
                {
                case WM_CANCELMODE:
                    this->DoOnCancelMode(message);
                    break;
                case WM_CHAR:
                    this->DoOnChar(message);
                    break;
                case WM_CHARTOITEM:
                    this->DoOnCharToItem(message);
                    break;
                case WM_CLOSE:
                    this->DoOnClose(message);
                    break;
                case WM_COMPAREITEM:
                    this->DoOnCompareItem(message);
                    break;
                case WM_COMMAND:
                    if(message.lParam != 0)
                    {
                        HWND hWnd = (HWND)message.lParam;
                        LRESULT result = ::SendMessageW(hWnd,REFLECTED_WM_COMMAND,message.wParam,message.lParam);
                        if(result)
                        {
                            message.result = 0;
                            return;
                        }
                    }
                    this->DoOnCommand(message);
                    break;
                case WM_COPYDATA:
                    this->DoOnCopyData(message);
                    break;
                case WM_DEADCHAR:
                    this->DoOnDeadChar(message);
                    break;
                case WM_DELETEITEM:
                    this->DoOnDeleteItem(message);
                    break;
                case WM_DESTROY:
                    this->DoOnDestroy(message);
                    break;
                case WM_DISPLAYCHANGE:
                    this->DoOnDisplayChange(message);
                    break;
                case WM_DRAWITEM:
                    this->DoOnDrawItem(message);
                    break;
                case WM_ENABLE:
                    this->DoOnEnable(message);
                    break;
                case WM_ENTERSIZEMOVE:
                    this->DoOnEnterSizeMove(message);
                    break;
                case WM_ERASEBKGND:
                    this->DoOnEraseBackground(message);
                    break;
                case WM_EXITSIZEMOVE:
                    this->DoOnExitSizeMove(message);
                    break;
                case WM_GETHOTKEY:
                    this->DoOnGetHotKey(message);
                    break;
                case WM_GETTEXT:
                    this->DoOnGetText(message);
                    break;
                case WM_GETTEXTLENGTH:
                    this->DoOnGetTextLength(message);
                    break;
                case WM_INITMENU:
                    this->DoOnInitMenu(message);
                    break;
                case WM_KEYDOWN:
                    this->DoOnKeyDown(message);
                    break;
                case WM_KEYUP:
                    this->DoOnKeyUp(message);
                    break;
                case WM_KILLFOCUS:
                    this->DoOnKillFocus(message);
                    break;
                case WM_MEASUREITEM:
                    this->DoOnMeasureItem(message);
                    break;
                case WM_MENUCOMMAND:
                    this->DoOnMenuCommand(message);
                    break;
                case WM_MOUSEMOVE:
                    this->DoOnMouseMove(message);
                    break;
                case WM_LBUTTONDOWN:
                    this->DoOnMouseLeftButtonDown(message);
                    break;
                case WM_LBUTTONUP:
                    this->DoOnMouseLeftButtonUp(message);
                    break;
                case WM_LBUTTONDBLCLK:
                    this->DoOnMouseLeftButtonDoubleClick(message);
                    break;
                case WM_RBUTTONDOWN:
                    this->DoOnMouseRightButtonDown(message);
                    break;
                case WM_RBUTTONUP:
                    this->DoOnMouseRightButtonUp(message);
                    break;
                case WM_RBUTTONDBLCLK:
                    this->DoOnMouseRightButtonDoubleClick(message);
                    break;
                case WM_MBUTTONDOWN:
                    this->DoOnMouseMiddleButtonDown(message);
                    break;
                case WM_MBUTTONUP:
                    this->DoOnMouseMiddleButtonUp(message);
                    break;
                case WM_MBUTTONDBLCLK:
                    this->DoOnMouseMiddleButtonDoubleClick(message);
                    break;
                case WM_XBUTTONDOWN:
                    this->DoOnMouseXButtonDown(message);
                    break;
                case WM_XBUTTONUP:
                    this->DoOnMouseXButtonUp(message);
                    break;
                case WM_XBUTTONDBLCLK:
                    this->DoOnMouseXButtonDoubleClick(message);
                    break;
                case WM_MOUSEHWHEEL:
                    this->DoOnMouseWheel(message);
                    break;
                case WM_MOVE:
                    position.Set((int)(short) LOWORD(message.lParam),(int)(short) HIWORD(message.lParam));
                    this->DoOnMove(message);
                    break;
                case WM_MOVING:
                    this->DoOnMoving(message);
                    break;
                case WM_NCACTIVATE:
                    this->DoOnNcActivate(message);
                    break;
                case WM_NCCALCSIZE:
                    this->DoOnNcCalcSize(message);
                    break;
                case WM_NCDESTROY:
                    this->DoOnNcDestroy(message);
                    break;
                case WM_NOTIFY:
                    {
                        NMHDR* nmhdr = (NMHDR*)message.lParam;
                        if(nmhdr)
                        {
                            HWND hWnd = nmhdr->hwndFrom;
                            message.result = ::SendMessageW(hWnd,REFLECTED_WM_NOTIFY,message.wParam,message.lParam);
                        }
                    }
                    break;
                case WM_PAINT:
                    this->DoOnPaint(message);
                    break;
                case WM_SETCURSOR:
                    this->DoOnSetCursor(message);
                    break;
                case WM_SETFOCUS:
                    this->DoOnSetFocus(message);
                    break;
                case WM_SETHOTKEY:
                    this->DoOnSetHotKey(message);
                    break;
                case WM_SETREDRAW:
                    this->DoOnSetRedraw(message);
                    break;
                case WM_SETTEXT:
                    this->DoOnSetText(message);
                    break;
                case WM_SHOWWINDOW:
                    this->DoOnShowWindow(message);
                    break;
                case WM_SIZE:
                    {
                    RECT rect = {0,};
                    GetWindowRect(message.hwnd,&rect);
                    size.Set(rect.right - rect.left,rect.bottom - rect.top);
                    this->DoOnSize(message);
                    }
                    break;
                case WM_SIZING:
                    this->DoOnSizing(message);
                    break;
                case WM_SYSCHAR:
                    this->DoOnSysChar(message);
                    break;
                case WM_SYSCOMMAND:
                    this->DoOnSysCommand(message);
                    break;
                case WM_SYSDEADCHAR:
                    this->DoOnSysDeadChar(message);
                    break;
                case WM_SYSKEYDOWN:
                    this->DoOnSysKeyDown(message);
                    break;
                case WM_SYSKEYUP:
                    this->DoOnSysKeyUp(message);
                    break;
                case WM_UNICHAR:
                    this->DoOnUniChar(message);
                    break;
                case WM_VKEYTOITEM:
                    this->DoOnVKeyToItem(message);
                    break;
                case WM_WINDOWPOSCHANGING:
                    this->DoOnWindowPosChanging(message);
                    break;
                case WM_WINDOWPOSCHANGED:
                    this->DoOnWindowPosChanged(message);
                    break;
                }
            }
        }

        HWIN_EXPORT void Control::DoOnCancelMode(Message& message)
        {
            OnCancelMode(this,message);
        }

        HWIN_EXPORT void Control::DoOnChar(Message& message)
        {
            OnChar(this,message);
        }

        HWIN_EXPORT void Control::DoOnCharToItem(Message& message)
        {
            OnCharToItem(this,message);
        }

        HWIN_EXPORT void Control::DoOnClose(Message& message)
        {
            OnClose(this,message);
        }

        HWIN_EXPORT void Control::DoOnCompareItem(Message& message)
        {
            OnCompareItem(this,message);
        }

        HWIN_EXPORT void Control::DoOnCommand(Message& message)
        {
            OnCommand(this,message);
        }

        HWIN_EXPORT void Control::DoOnCopyData(Message& message)
        {
            OnCopyData(this,message);
        }

        HWIN_EXPORT void Control::DoOnDeadChar(Message& message)
        {
            OnDeadChar(this,message);
        }

        HWIN_EXPORT void Control::DoOnDeleteItem(Message& message)
        {
            OnDeleteItem(this,message);
        }

        HWIN_EXPORT void Control::DoOnDestroy(Message& message)
        {
            OnDestroy(this,message);
        }

        HWIN_EXPORT void Control::DoOnDisplayChange(Message& message)
        {
            OnDisplayChange(this,message);
        }

        HWIN_EXPORT void Control::DoOnDrawItem(Message& message)
        {
            OnDrawItem(this,message);
            if(!message.handled)
            {
                DRAWITEMSTRUCT* drawItemStruct = (DRAWITEMSTRUCT*)message.lParam;
                if(drawItemStruct && drawItemStruct->CtlType == ODT_MENU)
                {
                    MenuItem* menuItem = (MenuItem*)drawItemStruct->itemData;
                    if(menuItem)
                    {
                        menuItem->DoOnDrawItem(*drawItemStruct);
                        message.handled = true;
                        message.result = true;
                    }
                }
            }
        }

        HWIN_EXPORT void Control::DoOnEnable(Message& message)
        {
            OnEnable(this,message);
        }

        HWIN_EXPORT void Control::DoOnEnterSizeMove(Message& message)
        {
            OnEnterSizeMove(this,message);
        }

        HWIN_EXPORT void Control::DoOnEraseBackground(Message& message)
        {
            OnEraseBackground(this,message);
        }

        HWIN_EXPORT void Control::DoOnExitSizeMove(Message& message)
        {
            OnExitSizeMove(this,message);
        }

        HWIN_EXPORT void Control::DoOnGetHotKey(Message& message)
        {
            OnGetHotKey(this,message);
        }

        HWIN_EXPORT void Control::DoOnGetText(Message& message)
        {
            OnGetText(this,message);
        }

        HWIN_EXPORT void Control::DoOnGetTextLength(Message& message)
        {
            OnGetTextLength(this,message);
        }

        HWIN_EXPORT void Control::DoOnInitMenu(Message& message)
        {
            OnInitMenu(this,message);
            if(!message.handled)
            {
                HMENU hMenu = (HMENU)message.lParam;
                if(hMenu)
                {
                    auto menu = Menu::GetFromMenuMap(hMenu);
                    if(menu)
                    {
                        menu->DoOnInitMenu(message);
                    }
                }
            }
        }

        HWIN_EXPORT void Control::DoOnInitMenuPopup(Message& message)
        {
            OnInitMenuPopup(this,message);
            if(!message.handled)
            {
                HMENU hMenu = (HMENU)message.wParam;
                if(hMenu)
                {
                    auto menu = Menu::GetFromMenuMap(hMenu);
                    if(menu)
                    {
                        menu->DoOnInitMenuPopup(message);
                    }
                }
            }
        }


        HWIN_EXPORT void Control::DoOnKeyDown(Message& message)
        {
            OnKeyDown(this,message);
        }

        HWIN_EXPORT void Control::DoOnKeyUp(Message& message)
        {
            OnKeyUp(this,message);
        }

        HWIN_EXPORT void Control::DoOnKillFocus(Message& message)
        {
            OnKillFocus(this,message);
        }

        HWIN_EXPORT void Control::DoOnMeasureItem(Message& message)
        {
            OnMeasureItem(this,message);
            if(!message.handled)
            {
                MEASUREITEMSTRUCT* measureItemStruct = (MEASUREITEMSTRUCT*)message.lParam;
                if(measureItemStruct && measureItemStruct->CtlType == ODT_MENU)
                {
                    MenuItem* menuItem = (MenuItem*)measureItemStruct->itemData;
                    if(menuItem)
                    {
                        menuItem->DoOnMeasureItem(*measureItemStruct);
                        message.handled = true;
                        message.result = true;
                    }
                }
            }
        }

        HWIN_EXPORT void Control::DoOnMenuCommand(Message& message)
        {
            OnMenuCommand(this,message);
            if(!message.handled)
            {
                HMENU hMenu = (HMENU)message.lParam;
                if(hMenu)
                {
                    auto menu = Menu::GetFromMenuMap(hMenu);
                    if(menu)
                    {
                        menu->DoOnMenuCommand(message);
                    }
                }
            }
        }

        HWIN_EXPORT void Control::DoOnMouseMove(Message& message)
        {
            OnMouseMove(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseLeftButtonDown(Message& message)
        {
            OnMouseLeftButtonDown(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseLeftButtonUp(Message& message)
        {
            OnMouseLeftButtonUp(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseLeftButtonDoubleClick(Message& message)
        {
            OnMouseLeftButtonDoubleClick(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseMiddleButtonDown(Message& message)
        {
            OnMouseMiddleButtonDown(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseMiddleButtonUp(Message& message)
        {
            OnMouseMiddleButtonUp(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseMiddleButtonDoubleClick(Message& message)
        {
            OnMouseMiddleButtonDoubleClick(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseRightButtonDown(Message& message)
        {
            OnMouseRightButtonDown(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseRightButtonUp(Message& message)
        {
            OnMouseRightButtonUp(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseRightButtonDoubleClick(Message& message)
        {
            OnMouseRightButtonDoubleClick(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseXButtonDown(Message& message)
        {
            OnMouseXButtonDown(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseXButtonUp(Message& message)
        {
            OnMouseXButtonUp(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseXButtonDoubleClick(Message& message)
        {
            OnMouseXButtonDoubleClick(this,message);
        }

        HWIN_EXPORT void Control::DoOnMouseWheel(Message& message)
        {
            OnMouseWheel(this,message);
        }



        HWIN_EXPORT void Control::DoOnMove(Message& message)
        {
            OnMove(this,message);
        }

        HWIN_EXPORT void Control::DoOnMoving(Message& message)
        {
            OnMoving(this,message);
        }

        HWIN_EXPORT void Control::DoOnNcActivate(Message& message)
        {
            OnNcActivate(this,message);
        }    

        HWIN_EXPORT void Control::DoOnNcCalcSize(Message& message)
        {
            OnNcCalcSize(this,message);
        }

        HWIN_EXPORT void Control::DoOnNcDestroy(Message& message)
        {
            OnNcDestroy(this,message);
        }

        HWIN_EXPORT void Control::DoOnNotify(Message& message)
        {
            OnNotify(this,message);
        }

        HWIN_EXPORT void Control::DoOnPaint(Message& message)
        {
            OnPaint(this,message);
        }

        HWIN_EXPORT void Control::DoOnSetCursor(Message& message)
        {
            OnSetCursor(this,message);
        }

        HWIN_EXPORT void Control::DoOnSetFocus(Message& message)
        {
            OnSetFocus(this,message);
        }

        HWIN_EXPORT void Control::DoOnSetHotKey(Message& message)
        {
            OnSetHotKey(this,message);
        }

        HWIN_EXPORT void Control::DoOnSetRedraw(Message& message)
        {
            OnSetRedraw(this,message);
        }

        HWIN_EXPORT void Control::DoOnSetText(Message& message)
        {
            OnSetText(this,message);
        }
        HWIN_EXPORT void Control::DoOnShowWindow(Message& message)
        {
            OnShowWindow(this,message);
        }

        HWIN_EXPORT void Control::DoOnSize(Message& message)
        {
            OnSize(this,message);
        }

        HWIN_EXPORT void Control::DoOnSizing(Message& message)
        {
            OnSizing(this,message);
        }

        HWIN_EXPORT void Control::DoOnSysChar(Message& message)
        {
            OnSysChar(this,message);
        }

        HWIN_EXPORT void Control::DoOnSysCommand(Message& message)
        {
            OnSysCommand(this,message);
        }

        HWIN_EXPORT void Control::DoOnSysDeadChar(Message& message)
        {
            OnSysDeadChar(this,message);
        }

        HWIN_EXPORT void Control::DoOnSysKeyDown(Message& message)
        {
            OnSysKeyDown(this,message);
        }

        HWIN_EXPORT void Control::DoOnSysKeyUp(Message& message)
        {
            OnSysKeyUp(this,message);
        }


        HWIN_EXPORT void Control::DoOnUniChar(Message& message)
        {
            OnUniChar(this,message);
        }

        HWIN_EXPORT void Control::DoOnVKeyToItem(Message& message)
        {
            OnVKeyToItem(this,message);
        }

        HWIN_EXPORT void Control::DoOnWindowPosChanging(Message& message)
        {
            OnWindowPosChanging(this,message);
        }

        HWIN_EXPORT void Control::DoOnWindowPosChanged(Message& message)
        {
            OnWindowPosChanged(this,message);
        }







    };
};